// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/AsyncTasks/ListenCooldownChange.h"

#include "AbilitySystemComponent.h"

UListenCooldownChange* UListenCooldownChange::ListenCooldownChange(
	UAbilitySystemComponent* InASC, const FGameplayTag InCooldownTag
)
{
	UListenCooldownChange* ListenCooldownChange = NewObject<UListenCooldownChange>();
	ListenCooldownChange->ASC = InASC;
	ListenCooldownChange->CooldownTag = InCooldownTag;

	if (!IsValid(InASC) || !InCooldownTag.IsValid())
	{
		ListenCooldownChange->EndTask();
		return nullptr;
	}

	//标签变动委托绑定监听冷却标签函数
	InASC->RegisterGameplayTagEvent(InCooldownTag, EGameplayTagEventType::NewOrRemoved)
	   .AddUObject(ListenCooldownChange, &UListenCooldownChange::CooldownTagChange);

	//GE应用到自身触发的委托绑定监听函数
	InASC->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(
		ListenCooldownChange,
		&UListenCooldownChange::OnActiveEffectAdded
	);

	return ListenCooldownChange;
}

void UListenCooldownChange::EndTask()
{
	if (ASC)
	{
		//取消对冷却标签的变动监听
		ASC->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved)
		   .RemoveAll(this);

		//设置此对象可以被销毁，如果此对象不再被引用，将可以被销毁掉
		SetReadyToDestroy();

		//标记此实例为垃圾资源，可以被回收
		MarkAsGarbage();
	}
}

void UListenCooldownChange::CooldownTagChange(const FGameplayTag InCooldownTag, const int32 NewCount) const
{
	//如果计数为0，代表冷却标签已经不存在，技能不处于冷却状态
	if (NewCount == 0)
	{
		//广播冷却结束委托
		CooldownEnd.Broadcast(0.f);
	}
}

void UListenCooldownChange::OnActiveEffectAdded(
	UAbilitySystemComponent* InASC, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveHandle
) const
{
	//获取该应用到自身的效果的所有标签
	FGameplayTagContainer AssetTags;
	SpecApplied.GetAllAssetTags(AssetTags);

	//获取该应用到自身的效果的用于授予的标签
	FGameplayTagContainer GrantedTags;
	SpecApplied.GetAllGrantedTags(GrantedTags);

	//判断应用的GE是否设置了此冷却标签
	if (AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag))
	{
		//创建一个查询对象，用于查询所有包含冷却标签的GE
		const FGameplayEffectQuery GameplayEffectQuery = FGameplayEffectQuery::MakeQuery_MatchAllOwningTags(
			CooldownTag.GetSingleTagContainer()
		);
		//获取冷却GE的剩余时间
		TArray<float> TimesRemaining = ASC->GetActiveEffectsTimeRemaining(GameplayEffectQuery);
		if (TimesRemaining.Num() > 0)
		{
			//获取最高的冷却时间
			float TimeRemaining = TimesRemaining[0];
			for (const float& Time : TimesRemaining)
			{
				if (Time > TimeRemaining)
				{
					TimeRemaining = Time;
				}
			}
			//广播初始时间
			CooldownStart.Broadcast(TimeRemaining);
		}
	}
}
